<script lang="ts" setup>
import type { Ref } from "vue";
import type { FormActionType, FormProps, FormSchema } from "./types";
import { useFormEvents } from "./hooks/useFormEvents";
import { useAttrs, computed, ref, unref, onMounted } from "vue";
import VeFormItem from "./components/FormItem.vue";
const attrs = useAttrs();
const emit = defineEmits(["register"]);
const props = defineProps();
const propsRef = ref<Partial<FormProps>>({});
const formRef = ref(null);

const getBindValue = computed(() => ({
  ...attrs,
  ...props,
  ...propsRef.value,
}));

const getSchema = computed(() => {
  const { schemas } = unref(propsRef);
  return schemas || [];
});

const { validate, resetFields, clearValidate, scrollToField, validateField } =
  useFormEvents({
    propsRef,
    formElRef: formRef as Ref,
  });

function setFormModel(key: string, value: any) {
  if (propsRef.value.model) {
    propsRef.value.model[key] = value;
  }
}

function setProps(formProps: Partial<FormProps>) {
  const model: any = {};
  formProps.schemas?.map(
    (x: any) =>
      (model[x.field] = "defaultValue" in x ? x.defaultValue : undefined)
  );
  propsRef.value.model = model;
  propsRef.value = { ...propsRef.value, ...unref(formProps) };
}

function setFiledsValue(value: any) {
  resetFields();
  Object.assign(propsRef.value.model, value);
}
function updateSchemaByField(key, value) {
  const { schemas } = propsRef.value;
  schemas?.forEach((x) => {
    if (x.field === key) {
      Object.assign(x, value);
    }
  });
}
function updateSchema(v: FormSchema[]) {
  const { schemas } = propsRef.value as any;
  for (let i = 0; i < v.length; i++) {
    for (let j = 0; j < schemas?.length; j++) {
      if (v[i]["field"] === schemas[j]["field"]) {
        Object.assign(schemas[j], v[i]);
      }
    }
  }
}
function removeSchemaByField(key) {
  const { schemas } = propsRef.value;
  const index: any = schemas?.findIndex((x) => x.field === key);
  if (index > -1) {
    schemas?.splice(index, 1);
  }
}
function appendSchemaByField(schema: FormSchema, prefixField, first = false) {
  const { schemas } = propsRef.value;
  if (first) {
    schemas?.unshift(schema);
  } else {
    const index: any = schemas?.findIndex((x) => x.field === prefixField);
    if (index > -1) {
      schemas?.splice(index + 1, 0, schema);
    } else {
      schemas?.push(schema);
    }
  }
}
const formAction: Partial<FormActionType> = {
  setProps,
  validate,
  resetFields,
  clearValidate,
  scrollToField,
  validateField,
  setFiledsValue,
  updateSchema,
  removeSchemaByField,
  updateSchemaByField,
  appendSchemaByField,
};

// 暴露给外面的组件实例使用
defineExpose(formAction);

onMounted(() => {
  emit("register", formAction);
});
</script>

<template>
  <a-form ref="formRef" v-bind="getBindValue">
    <slot name="formHeader"></slot>
    <a-row :gutter="24">
      <template v-for="schema in getSchema" :key="schema.field">
        <a-col v-bind="schema.colProps || { span: 24 }">
          <slot :name="schema?.slot" v-if="$slots[schema?.slot]"></slot>
          <VeFormItem
            :schema="schema"
            :formProps="propsRef"
            :setFormModel="setFormModel"
            v-else
          >
            <template #[item]="data" v-for="item in Object.keys($slots)">
              <slot :name="item" v-bind="data || {}"></slot>
            </template>
          </VeFormItem>
        </a-col>
      </template>
    </a-row>
    <slot name="formFooter"></slot>
  </a-form>
</template>
